package bll

import (
	"context"
	"fmt"
	"gorm.io/gorm"
	log "ota/collector/logger"
	"ota/errors"
	"ota/event"
	"ota/utils"
	"unicode/utf8"

	"github.com/lib/pq"

	"ota/model"
	"ota/model/entity"
	"ota/model/mapping"
	"ota/store"
	"ota/store/postgres"
	"time"
)

type firmware struct {
	iFirmware store.IFirmware
}

var (
	maxNameLength = 30
	Firmware      = &firmware{
		iFirmware: postgres.Firmware,
	}
)

func init() {
	Register(Firmware)
}

func (a *firmware) init() func() {
	return func() {}
}

func (a *firmware) onEvent(*event.Data) {}

func (a *firmware) checkExist(ctx context.Context, name string) bool {

	// 固件名称校验
	var count int64
	postgres.GetDB(ctx).Model(&entity.Firmware{}).Where("name = ?", name).Count(&count)
	if count > 0 {
		return true
	}

	return false
}

func (a *firmware) check(ctx context.Context, id int64, op model.OtaFirmwareOpType) error {

	respFirmware, err := a.iFirmware.Find(ctx, &model.FirmwareInfoRequest{Id: id})
	if err != nil {
		log.Errorf("get upgrade strategy err: %v", err)
		if !errors.Is(err, gorm.ErrRecordNotFound) {
			return errors.InternalServerError.Error()
		}
	}
	if respFirmware.Id == 0 {
		return errors.FirmwareNotExist.Error()
	}
	if _, data, err := UpgradeStrategy.iUpgradeStrategy.List(ctx, &model.UpgradeStrategyListRequest{
		Index:      1,
		Size:       1,
		FirmwareId: utils.GetValuePointer(respFirmware.Id),
	}, model.QueryOptions{
		OnlyList: true,
	}); err != nil {
		log.Errorf("get upgrade plan err: %v", err)
		return errors.InternalServerError.Error()
	} else {
		if len(data) > 0 {
			if op == model.FirmwareOpDelete {
				return fmt.Errorf("已有升级策略(%v %v)关联该固件，不允许删除", data[0].Id, data[0].Name)
			}
		}
	}

	return nil
}

// Create
func (a *firmware) Create(ctx context.Context, in *model.FirmwareCreateRequest) error {

	if utf8.RuneCountInString(in.Name) > maxNameLength {
		return fmt.Errorf("请输入15字符内的固件名称")
	}

	if b := a.checkExist(ctx, in.Name); b {
		return fmt.Errorf("固件名称已存在")
	}

	var (
		err error
	)
	c := buildFirmware(in)
	_, err = a.iFirmware.Create(ctx, c)
	return err
}

// Update
func (a *firmware) Update(ctx context.Context, in *model.FirmwareUpdateRequest) error {

	if err := a.check(ctx, *in.Id, model.FirmwareOpUpdate); err != nil {
		return err
	}

	var (
		dict = make(map[string]interface{})
	)

	if in.Id != nil {
		dict["id"] = in.Id
	}

	if in.TypeIds != nil {
		dict["type_ids"] = in.TypeIds
	}

	if in.Name != nil {
		if utf8.RuneCountInString(*in.Name) > maxNameLength {
			return fmt.Errorf("输入15字符内的固件名称")
		}
		dict["name"] = in.Name
	}

	if in.FileSize != nil {
		dict["file_size"] = in.FileSize
	}

	if in.Description != nil {
		dict["description"] = in.Description
	}

	if in.FilePath != nil {
		dict["file_path"] = in.FilePath
	}

	if in.Version != nil {
		dict["version"] = in.Version
	}

	if in.CreatedAt != nil {
		dict["created_at"] = in.CreatedAt
	}

	if in.UpdatedAt != nil {
		dict["updated_at"] = in.UpdatedAt
	}

	// do other update here
	updateAt := time.Now().Unix()
	in.UpdatedAt = &updateAt
	return a.iFirmware.Update(ctx, *in.Id, dict)
}

// Delete
func (a *firmware) Delete(ctx context.Context, in *model.FirmwareDeleteRequest) error {

	if err := a.check(ctx, in.Id, model.FirmwareOpDelete); err != nil {
		return err
	}
	return a.iFirmware.Delete(ctx, in.Id)
}

// List
func (a *firmware) List(ctx context.Context, in *model.FirmwareListRequest) (*model.FirmwareListResponse, error) {
	var (
		err   error
		total int
		list  []*model.FirmwareDetailInfo
		out   = &model.FirmwareListResponse{}
		opts  = model.QueryOptions{OrderFields: model.NewOrderFields(model.NewOrderField("created_at", model.OrderByDESC))}
	)

	if total, list, err = a.iFirmware.List(ctx, in, opts); err != nil {
		return nil, err
	}

	out.Total = total
	out.List = list

	return out, nil
}

// Find
func (a *firmware) Find(ctx context.Context, in *model.FirmwareInfoRequest) (*model.FirmwareInfo, error) {
	var (
		err  error
		data *entity.Firmware
		out  = &model.FirmwareInfo{}
	)

	if data, err = a.iFirmware.Find(ctx, in); err != nil {
		return nil, err
	}

	out = mapping.FirmwareEntityToDto(data)
	return out, nil
}

// Find
func (a *firmware) FindDetail(ctx context.Context, in *model.FirmwareInfoRequest) (*model.FirmwareDetailInfo, error) {
	var (
		err  error
		data *model.FirmwareDetailInfo
	)

	if data, err = a.iFirmware.FindDetail(ctx, in); err != nil {
		return nil, err
	}

	return data, nil
}

// buildFirmware build entity
func buildFirmware(in *model.FirmwareCreateRequest) *entity.Firmware {

	ety := &entity.Firmware{

		FilePath: "",
	}

	ety.Id = in.Id

	if len(in.TypeIds) != 0 {
		ety.TypeIds = in.TypeIds
	} else {
		ety.TypeIds = pq.Int64Array{}
	}

	ety.Name = in.Name

	ety.FileSize = in.FileSize

	ety.FilePath = in.FilePath

	ety.Description = in.Description

	ety.Version = in.Version

	ety.CreatedAt = time.Now().Unix()

	ety.UpdatedAt = in.UpdatedAt

	return ety
}
